﻿using System;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;

namespace Gems
{
    public class UdpUnicastLink : IUnicastLink, IDisposable
    {
        readonly UdpClient _client;
        private readonly int _port;

        public UdpUnicastLink(int port)
        {
            _port = port;
            _client = new UdpClient(port);
            _client.BeginReceive(ReceiveCallback, null);
        }

        public void Send(string hostName, byte[] data)
        {
            _client.BeginSend(data, data.Length, hostName, _port, SendCallback, null);
        }

        public async Task<int> SendAsync(string hostName, byte[] data)
        {
            Socket s = null;

            var hostEntry = await DnsEx.GetHostEntryAsync(hostName);
            
            foreach (var address in hostEntry.AddressList)
            {
                var ipe = new IPEndPoint(address, _port);
                
                s = new Socket(ipe.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

                await s.ConnectAsync2(ipe);

                if (s.Connected)
                {
                    break;
                }
                
            }

            return await s.SendAsync2(data);
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            var from = new IPEndPoint(IPAddress.IPv6Any, 0);
            var receivedBytes = _client.EndReceive(ar, ref from);
            _client.BeginReceive(ReceiveCallback, null);
            OnReceived(receivedBytes);
        }

        private void SendCallback(IAsyncResult ar)
        {
            _client.EndSend(ar);
        }

        public event OnDataReceived Received;

        public void OnReceived(byte[] data)
        {
            OnDataReceived handler = Received;
            if (handler != null) handler(data);
        }

        public void Dispose()
        {
            _client.Close();
        }
    }
}
